import requests
import os
import json
import time
import argparse
from urllib.parse import quote
import urllib3
import ast

from utils.configs import CodeartsConfig, GiteeConfig, NEED_REPORT_CI_JOBS
from utils.obs_tool import ObsTool
from check_runs2 import create_check, update_check
from web_request_process.gitee_process import GiteePrLabelProcess, GiteePrCommentProcess, GiteePrPiplineLabel, GiteePrInfoProcess
from web_request_process.jenkins_process import JenkinsJobProcess

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

SMOKE_JOB_NAME = "SMOKE"


def get_token():
    headers = {"Content-Type": "application/json"}
    token_url = f"https://iam.{CodeartsConfig.REGION}.myhuaweicloud.com/v3/auth/tokens"
    token_body = {
        "auth": {
            "identity": {
                "methods": [
                    "password"
                ],
                "password": {
                    "user": {
                        "domain": {
                            "name": CodeartsConfig.DOMAIN_NAME
                        },
                        "name": CodeartsConfig.IAM_USER_NAME,
                        "password": "y621r4^0f1en>e72z5el2k2sf"
                    }
                }
            },
            "scope": {
                "project": {
                    "name": CodeartsConfig.REGION
                }
            }
        }
    }

    response = requests.post(
        url=token_url, data=json.dumps(token_body), headers=headers)
    print(f"get token response status: {response.status_code}")
    return response.headers.get("X-Subject-Token")


def get_log(job_name, job_number, params):
    """
    获取Jenkins log转存到执行机；上传log到obs；获取分享下载链接
    """
    print(f"获取{job_name}的Jenkins log...")
    local_log_save_path = os.path.join(params.project_dir, params.pipeline_number, "logs", job_name)
    local_jenkins_log_path = os.path.join(local_log_save_path, f"{job_name}_{job_number}_console.log")
    jenkins_job = JenkinsJobProcess(job_name, job_number)
    jenkins_job.save_log(local_jenkins_log_path)

    # 冒烟有多个log，打包成zip
    log_zip_path = f"{local_log_save_path}.zip"
    os.system(f"zip -r {log_zip_path} {local_log_save_path}/")
    
    # TODO
    obs_log_save_path = os.path.join("logs", f"{job_name}.zip")
    obs_tool = ObsTool(job_name, params.pipeline_number)
    obs_tool.upload(log_zip_path, obs_log_save_path)
    return obs_tool.get_download_url(obs_log_save_path)


def get_job_number(params, jenkins_job_name):
    """
    读取机器上指定路径的文件，获取流水线执行号对应的Jenkins任务id
    """
    data_info_file_path = os.path.join(params.project_dir, params.pipeline_number, "json_info", f"{jenkins_job_name}.json")
    with open(data_info_file_path, "r") as f:
        data_info = json.load(f)
    return data_info.get("number")


def get_ci_report_process(pipeline_status_response, merge_id, current_stage_name, params):
    result_dict = {}
    stages = pipeline_status_response.json().get("stages")
    stage_index = list(NEED_REPORT_CI_JOBS.keys()).index(current_stage_name)
    need_stages = list(NEED_REPORT_CI_JOBS.keys())[:(stage_index + 1)]
    print(f"需要查找状态的stages：{need_stages}")
    for stage in stages:
        stage_name = stage.get("name")
        if stage_name not in need_stages:
            continue
        need_report_jobs = NEED_REPORT_CI_JOBS.get(stage_name, {})
        jobs = stage.get("jobs")
        for job in jobs:
            job_name = job.get("name")
            if job_name not in need_report_jobs:
                continue
            print(f"job name: {job_name}, job status: {job.get('status')}")
            result_dict[job_name] = [need_report_jobs.get(job_name), job.get("status")]

    if not all([(x[-1] != "RUNNING" and  x[-1] != "QUEUED") for x in result_dict.values()]):
        # 存在还处于running状态的job则先返回
        return None, None

    # 更新当前对应stage中job的门禁检查项状态
    current_stage_jobs = NEED_REPORT_CI_JOBS.get(current_stage_name)
    pr_info = GiteePrInfoProcess(merge_id)
    pr_info = pr_info.get_info()
    pr_id = GiteePrInfoProcess.get_pull_request_id(pr_info)
    for k, v in result_dict.items():
        # TODO 函数多个功能聚合，需要拆解
        # 流水线中不存在的阶段反查？
        if k not in current_stage_jobs:
            continue
        job_status = v[-1]
        job_ci_item_name = v[0].ci_check_item_name
        if job_status == "COMPLETED":
            update_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME, merge_id, job_ci_item_name, "completed",
                         "success", pull_request_id=pr_id)
        elif job_status == "FAILED":
            update_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME, merge_id, job_ci_item_name, "completed",
                         "failure", pull_request_id=pr_id)
        elif job_status == "UNSELECTED":
            update_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME, merge_id, job_ci_item_name, "completed",
                         "skipped", pull_request_id=pr_id)
        else:
            print(f"warning！{k}结果{job_status}不在正常范围")


    if all([(x[-1] == "COMPLETED" or x[-1] == "UNSELECTED") for x in result_dict.values()]) and stage_index < (len(NEED_REPORT_CI_JOBS) - 1):
        # 如果所有job都处于执行完成（成功）状态或跳过状态，且当前不处于最后一个stage时，不返回评论报告，在后续stage再返回评论结果
        return True, None

    # report
    map_dict = {"COMPLETED": "成功",
                "FAILED": "失败",
                "UNSELECTED": "跳过"}

    table_str = "<table><tr><th>阶段</th><th>结果</th><th>日志链接</th></tr>"
    for _, v in result_dict.items():
        # TODO
        log_url = get_log(v[0].jenkins_job_name, get_job_number(params, v[0].jenkins_job_name), params)
        table_str += f"<tr><td>{v[0].report_name}</td><td>{map_dict.get(v[-1])}</td><td><a href='{log_url}'>下载</a></td></tr>"

    # 如果上报report时，不处于最后一个stage，需要把后面的stage的门禁状态改成跳过/未执行
    not_run_stages = list(NEED_REPORT_CI_JOBS.keys())[(stage_index + 1):]
    for stage in not_run_stages:
        for _, job_info in NEED_REPORT_CI_JOBS.get(stage).items():
            update_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME, merge_id, job_info.ci_check_item_name, "completed",
                         "cancelled", pull_request_id=pr_id)
            table_str += f"<tr><td>{job_info.report_name}</td><td>未执行</td></tr>"

    table_str += "</table>"

    print(f"流水线执行结果：\n{table_str}")

    return all([(x[-1] == "COMPLETED" or x[-1] == "UNSELECTED") for x in result_dict.values()]), table_str


def get_pipeline_status_response(token, pipeline_run_id=None):
    headers = {"Content-Type": "application/json", "X-Auth-Token": token}

    # 有pipeline_run_id时获取指定执行时的流水线执行信息，没有时返回最新一次的流水线执行信息
    if pipeline_run_id:
        pipeline_run_url = f"https://cloudpipeline-ext.{CodeartsConfig.REGION}.myhuaweicloud.com/v5/{CodeartsConfig.PROJECT_ID}/api/pipelines/{CodeartsConfig.PIPELINE_ID}/pipeline-runs/detail"
        params = {"pipeline_run_id": pipeline_run_id}
        print("get pipeline info url, ", pipeline_run_url, pipeline_run_id)
        # print("======= params, ", params)
        # print("======= headers, ", headers)
        response = requests.get(url=pipeline_run_url,
                                headers=headers, params=params, verify=False)

        if not response.text:
            response = requests.get(url=pipeline_run_url,
                                    headers=headers, verify=False)
    else:
        pipeline_run_url = f"https://cloudpipeline-ext.{CodeartsConfig.REGION}.myhuaweicloud.com/v5/{CodeartsConfig.PROJECT_ID}/api/pipelines/{CodeartsConfig.PIPELINE_ID}/pipeline-runs/detail"
        response = requests.get(url=pipeline_run_url,
                                headers=headers, verify=False)

    return response


def add_running_label_to_pr(merge_id):
    # 流水线开始时把执行中状态的label加到gitee pr中
    if GiteePrLabelProcess(GiteePrPiplineLabel.FAILED.value, merge_id).search_existed():
        GiteePrLabelProcess(
            GiteePrPiplineLabel.FAILED.value, merge_id).delete()
    if GiteePrLabelProcess(GiteePrPiplineLabel.SUCCESS.value, merge_id).search_existed():
        GiteePrLabelProcess(
            GiteePrPiplineLabel.SUCCESS.value, merge_id).delete()
    pr_label = GiteePrLabelProcess(GiteePrPiplineLabel.RUNNING.value, merge_id)
    pr_label.add()


def add_ci_check_to_pr(merge_id, stage_name):
    pr_info = GiteePrInfoProcess(merge_id)
    pr_info = pr_info.get_info()
    # pr_head_sha = GiteePrInfoProcess.get_head_sha(pr_info)
    pr_id = GiteePrInfoProcess.get_pull_request_id(pr_info)
    print("将门禁检查项状态改为执行中...")
    for _, ci_job_info in NEED_REPORT_CI_JOBS.get(stage_name).items():
        # create_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME, merge_id, ci_job_info.ci_check_item_name)
        time.sleep(2)
        update_check(GiteeConfig.REPO_OWNER, GiteeConfig.REPO_NAME,
                     merge_id, ci_job_info.ci_check_item_name, "in_progress", pull_request_id=pr_id)


def pre_ci_process(merge_id, stage_name):
    add_ci_check_to_pr(merge_id, stage_name)


def waiting_pipeline_finish(token, params):
    merge_id = params.merge_id
    stage_name = params.stage_name
    pipeline_run_id = params.pipeline_run_id

    i = 0
    while i < 100:
        response = get_pipeline_status_response(token, pipeline_run_id)
        result, report_detail = get_ci_report_process(response, merge_id, stage_name, params)
        if not result and not report_detail:
            print("pipeline is running, waiting...")
            time.sleep(30)
            i += 1
            continue
        return result, report_detail


def send_gitee_comment_and_change_label(merge_id, pipeline_run_id, status, status_detail):
    pipline_url = f"https://devcloud.{CodeartsConfig.REGION}.huaweicloud.com/cicd/project/{CodeartsConfig.PROJECT_ID}/pipeline/detail/{CodeartsConfig.PIPELINE_ID}/{pipeline_run_id}"

    commit_process = GiteePrCommentProcess(merge_id)

    if not detail:
        return

    if status:
        commit_process.add(
            f''' :white_check_mark:  **门禁流水线执行完成！** [任务链接({pipeline_run_id})]({pipline_url})\n{status_detail}\n注意log分享链接有效期18小时''')
        # label = GiteePrPiplineLabel.SUCCESS.value
    else:
        commit_process.add(
            f''' :x:  **门禁流水线执行失败！** [任务链接({pipeline_run_id})]({pipline_url})\n{status_detail}\n注意log分享链接有效期18小时''')
        # label = GiteePrPiplineLabel.FAILED.value

    # running_pr_label = GiteePrLabelProcess(
    #     GiteePrPiplineLabel.RUNNING.value, merge_id)
    # if running_pr_label.search_existed():
    #     running_pr_label.change(label)
    # else:
    #     print(
    #         f"WARNING! 流水线执行完成，但是当前pr label似乎与预期不一致，{GiteePrPiplineLabel.RUNNING.value}并不存在！")
    #     GiteePrLabelProcess(label, merge_id).add()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--pipeline_run_id", type=str,
                        default="b56c4975eeef414e86bdb8e988920704")
    parser.add_argument("--merge_id", type=str,
                        help="MR Id or PR id", default="1")
    # 可以传入列表形态字符串，传入时需要按执行顺序传，添加门禁检查项只添加最后一个stage，也就是当前所在的stage。输出report时输出所有的
    parser.add_argument("--stage_name", type=str, default="SMOKE")
    parser.add_argument("--pipeline_number", type=str, default="249")
    parser.add_argument("--project_dir", type=str, default="/data/CI/Code")
    args, _ = parser.parse_known_args()
    print("开始添加标签扫描任务状态过程...")
    
    # 读取所有环境变量
    env_vars = os.environ
    # 打印每个环境变量的名称和值
    print("打印环境变量...")
    for var, value in env_vars.items():
        print(f'{var}: {value}')
    
    pre_ci_process(args.merge_id, args.stage_name)
    token = get_token()
    status, detail = waiting_pipeline_finish(token, args)
    send_gitee_comment_and_change_label(
        args.merge_id, args.pipeline_run_id, status, detail)
